{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import glob\n",
    "import os\n",
    "import sys\n",
    "\n",
    "sys.path.append(\"./src\")\n",
    "try:\n",
    "    sys.path.append(\n",
    "        glob.glob(\n",
    "            \"%s/PythonAPI/carla/dist/carla-*%d.%d-%s.egg\"\n",
    "            % (\n",
    "                os.environ.get(\"CARLA_ROOT\", \".\"),\n",
    "                sys.version_info.major,\n",
    "                sys.version_info.minor,\n",
    "                \"win-amd64\" if os.name == \"nt\" else \"linux-x86_64\",\n",
    "            )\n",
    "        )[0]\n",
    "    )\n",
    "except IndexError:\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import carla\n",
    "from replay_parser import Replay"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Initialize client and specify the replay file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Carla server will handle the decoding of the log file (to string)\n",
    "# If the replay is recorded with different version of Carla, errors may occur\n",
    "\n",
    "client = carla.Client(\"localhost\", 2000)\n",
    "client.set_timeout(5.0)\n",
    "\n",
    "# Note: Must provide absolute path to the log file\n",
    "filepath = os.path.abspath(\"./examples/data/Town01_record.dat\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Parsing the replay file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# By default, the replay will not parse all information immediately.\n",
    "# we will only parse what you need, when you call it.\n",
    "# In this script we will parse all information immediately.\n",
    "\n",
    "replay = Replay(client, filepath, lazy_init=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Episode information"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Town01 11.6\n"
     ]
    }
   ],
   "source": [
    "# From the replay file we can get the map name, duration of the record, \n",
    "print(replay.map_name, replay.duration)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Actors"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "# We provide access to all actors that are \"spawned\" in the world\n",
    "# Classify them into different types\n",
    "num_vehicles = len(replay.vehicles)\n",
    "num_walkers = len(replay.walkers)\n",
    "num_sensors = len(replay.sensors)\n",
    "num_obstacles = len(replay.obstacles)\n",
    "\n",
    "# Sensor is not considered as an \"actor\" since it cannot perform \"action\"\n",
    "print(len(replay.actors) == num_vehicles + num_walkers + num_obstacles)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "36\n"
     ]
    }
   ],
   "source": [
    "# There is a inner function called `_parse_actors` which is used to parse the actor information\n",
    "# If you need some other type of actors (for example TrafficLight), you can do:\n",
    "\n",
    "lights = replay._parse_actors(\"traffic.traffic_light\")\n",
    "print(len(lights))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Actor(id=198, blueprint='vehicle.tesla.model3', spawn_point=Location(x=-1.94737, y=24.961199999999998, z=0.00142345), attributes={'generation': '1', 'number_of_wheels': '4', 'sticky_control': 'true', 'object_type': '', 'color': '17,37,103', 'role_name': 'hero'}, sensors=[Actor(id=199, blueprint='sensor.other.collision', spawn_point=Location(x=-1.94737, y=24.961199999999998, z=0.00142345), attributes={'role_name': 'front'}, sensors=[]), Actor(id=200, blueprint='sensor.other.lane_invasion', spawn_point=Location(x=-1.94737, y=24.961199999999998, z=0.00142345), attributes={'role_name': 'front'}, sensors=[])])\n"
     ]
    }
   ],
   "source": [
    "# Each actor is a dataclass holding its \"id\", \"blueprint\", \"spawn_point\" and \"attributes\"\n",
    "# If the actor have some sensors attached, it will also have a \"sensors\" attribute\n",
    "\n",
    "print(replay.vehicles[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# You can retrieve the actor by its id or rolename\n",
    "\n",
    "replay.get_actor_by_id(198) == replay.get_actor_by_rolename(\"hero\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[Actor(id=198, blueprint='vehicle.tesla.model3', spawn_point=Location(x=-1.94737, y=24.961199999999998, z=0.00142345), attributes={'generation': '1', 'number_of_wheels': '4', 'sticky_control': 'true', 'object_type': '', 'color': '17,37,103', 'role_name': 'hero'}, sensors=[Actor(id=199, blueprint='sensor.other.collision', spawn_point=Location(x=-1.94737, y=24.961199999999998, z=0.00142345), attributes={'role_name': 'front'}, sensors=[]), Actor(id=200, blueprint='sensor.other.lane_invasion', spawn_point=Location(x=-1.94737, y=24.961199999999998, z=0.00142345), attributes={'role_name': 'front'}, sensors=[])]),\n",
       " Actor(id=201, blueprint='vehicle.lincoln.mkz_2020', spawn_point=Location(x=-1.9299199999999999, y=79.2626, z=-0.00502571), attributes={'generation': '2', 'number_of_wheels': '4', 'sticky_control': 'true', 'driver_id': '0', 'object_type': '', 'color': '0,0,0', 'role_name': 'car1'}, sensors=[Actor(id=202, blueprint='sensor.other.collision', spawn_point=Location(x=-1.9299199999999999, y=79.2626, z=-0.00502571), attributes={'role_name': 'front'}, sensors=[]), Actor(id=203, blueprint='sensor.other.lane_invasion', spawn_point=Location(x=-1.9299199999999999, y=79.2626, z=-0.00502571), attributes={'role_name': 'front'}, sensors=[])]),\n",
       " Actor(id=204, blueprint='vehicle.lincoln.mkz_2020', spawn_point=Location(x=2.1247, y=232.456, z=-0.005214079999999999), attributes={'generation': '2', 'number_of_wheels': '4', 'sticky_control': 'true', 'driver_id': '0', 'object_type': '', 'color': '0,0,0', 'role_name': 'car2'}, sensors=[Actor(id=205, blueprint='sensor.other.collision', spawn_point=Location(x=2.1247, y=232.456, z=-0.005214079999999999), attributes={'role_name': 'front'}, sensors=[]), Actor(id=206, blueprint='sensor.other.lane_invasion', spawn_point=Location(x=2.1247, y=232.456, z=-0.005214079999999999), attributes={'role_name': 'front'}, sensors=[])]),\n",
       " Actor(id=207, blueprint='vehicle.lincoln.mkz_2020', spawn_point=Location(x=2.10463, y=212.27, z=-0.00527058), attributes={'generation': '2', 'number_of_wheels': '4', 'sticky_control': 'true', 'driver_id': '0', 'object_type': '', 'color': '0,0,0', 'role_name': 'car3'}, sensors=[Actor(id=208, blueprint='sensor.other.collision', spawn_point=Location(x=2.10463, y=212.27, z=-0.00527058), attributes={'role_name': 'front'}, sensors=[]), Actor(id=209, blueprint='sensor.other.lane_invasion', spawn_point=Location(x=2.10463, y=212.27, z=-0.00527058), attributes={'role_name': 'front'}, sensors=[])]),\n",
       " Actor(id=210, blueprint='vehicle.tesla.cybertruck', spawn_point=Location(x=-2.0758, y=65.278, z=-0.00531578), attributes={'object_type': '', 'number_of_wheels': '4', 'sticky_control': 'true', 'generation': '2', 'role_name': 'car4'}, sensors=[Actor(id=216, blueprint='sensor.camera.rgb', spawn_point=Location(x=-1.94787, y=26.2612, z=1.80142), attributes={'chromatic_aberration_intensity': '0.0', 'tint': '0.0', 'shoulder': '0.26', 'toe': '0.55', 'white_clip': '0.04', 'slope': '0.88', 'blur_radius': '0.0', 'blur_amount': '1.0', 'blade_count': '5', 'exposure_speed_down': '1.0', 'min_fstop': '1.2', 'exposure_speed_up': '3.0', 'exposure_max_bright': '12.0', 'motion_blur_min_object_screen_size': '0.1', 'bloom_intensity': '0.675', 'lens_flare_intensity': '0.1', 'black_clip': '0.0', 'motion_blur_max_distortion': '0.35', 'focal_distance': '1000.0', 'motion_blur_intensity': '0.45', 'temp': '6500.0', 'gamma': '2.2', 'enable_postprocess_effects': 'true', 'iso': '100.0', 'shutter_speed': '200.0', 'exposure_compensation': '0.0', 'exposure_mode': 'histogram', 'calibration_constant': '16.0', 'lens_y_size': '0.08', 'lens_x_size': '0.08', 'lens_kcube': '0.0', 'lens_k': '-1.0', 'lens_circle_multiplier': '0.0', 'fstop': '1.4', 'fov': '90.0', 'image_size_y': '1080', 'chromatic_aberration_offset': '0.0', 'lens_circle_falloff': '5.0', 'image_size_x': '1920', 'sensor_tick': '0.0', 'exposure_min_bright': '10.0', 'role_name': 'front'}, sensors=[]), Actor(id=217, blueprint='sensor.other.imu', spawn_point=Location(x=-1.94737, y=24.961199999999998, z=0.00142345), attributes={'noise_gyro_stddev_y': '0.0', 'noise_gyro_stddev_x': '0.0', 'noise_gyro_stddev_z': '0.0', 'noise_accel_stddev_y': '0.0', 'noise_accel_stddev_x': '0.0', 'noise_accel_stddev_z': '0.0', 'noise_seed': '0', 'noise_gyro_bias_x': '0.0', 'sensor_tick': '0.0', 'noise_gyro_bias_z': '0.0', 'noise_gyro_bias_y': '0.0', 'role_name': 'default'}, sensors=[]), Actor(id=218, blueprint='sensor.lidar.ray_cast', spawn_point=Location(x=-1.94787, y=26.2612, z=1.80142), attributes={'noise_stddev': '0.0', 'dropoff_zero_intensity': '0.4', 'atmosphere_attenuation_rate': '0.004', 'horizontal_fov': '360.0', 'lower_fov': '-30.0', 'upper_fov': '15.0', 'rotation_frequency': '20.0', 'points_per_second': '250000', 'dropoff_intensity_limit': '0.8', 'noise_seed': '0', 'range': '100.0', 'channels': '32', 'dropoff_general_rate': '0.45', 'sensor_tick': '0.0', 'role_name': 'front'}, sensors=[]), Actor(id=219, blueprint='sensor.other.collision', spawn_point=Location(x=-1.94737, y=24.961199999999998, z=0.00142345), attributes={'role_name': 'front'}, sensors=[]), Actor(id=220, blueprint='sensor.other.lane_invasion', spawn_point=Location(x=-1.94737, y=24.961199999999998, z=0.00142345), attributes={'role_name': 'front'}, sensors=[])])]"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Support filter actors by their blueprint (wildcard is supported)\n",
    "\n",
    "replay.filter_actor_by_blueprint(\"vehicle.*\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Frames"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "233\n"
     ]
    }
   ],
   "source": [
    "# The replay file is recorded frame by frame (each `world.tick()`)\n",
    "\n",
    "print(len(replay.frame_info))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "frame_id: 1\n",
      "frame_time: 0.0\n",
      "transform: {198: Transform(location=Location(x=-1.94737, y=24.961199999999998, z=0.00137814), rotation=Rotation(pitch=0.0, yaw=0.0, roll=90.0221)), 201: Transform(location=Location(x=-1.9299199999999999, y=79.2626, z=-0.00502571), rotation=Rotation(pitch=0.0, yaw=0.0, roll=90.0221)), 204: Transform(location=Location(x=2.1247, y=232.456, z=-0.005214079999999999), rotation=Rotation(pitch=0.0, yaw=0.0, roll=-90.0299)), 207: Transform(location=Location(x=2.10463, y=212.27, z=-0.00527058), rotation=Rotation(pitch=-0.000671387, yaw=0.000662528, roll=-90.0299)), 210: Transform(location=Location(x=-2.0758, y=65.278, z=-0.00531578), rotation=Rotation(pitch=-0.000152588, yaw=0.000198075, roll=90.022))}\n",
      "velocity: {198: Vector3D(x=0, y=0, z=0), 201: Vector3D(x=0, y=0, z=0), 204: Vector3D(x=0, y=0, z=0), 207: Vector3D(x=0, y=0, z=0), 210: Vector3D(x=0, y=0, z=0)}\n",
      "acceleration: {198: Vector3D(x=0, y=0, z=0), 201: Vector3D(x=0, y=0, z=0), 204: Vector3D(x=0, y=0, z=0), 207: Vector3D(x=0, y=0, z=0), 210: Vector3D(x=0, y=0, z=0)}\n",
      "action: {198: Action(steering=0.0245669, throttle=1.0, brake=0.0, handbrake=False, gear=0, speed=None, type='vehicle'), 201: Action(steering=0.0, throttle=0.0, brake=0.0, handbrake=False, gear=0, speed=None, type='vehicle'), 204: Action(steering=0.0, throttle=0.0, brake=0.0, handbrake=False, gear=0, speed=None, type='vehicle'), 207: Action(steering=0.0, throttle=0.0, brake=0.0, handbrake=False, gear=0, speed=None, type='vehicle'), 210: Action(steering=0.0, throttle=0.0, brake=0.0, handbrake=False, gear=0, speed=None, type='vehicle')}\n"
     ]
    }
   ],
   "source": [
    "# Carla will only record minimal information that can allow it to play back\n",
    "# Actor is moving around by teleporting, all physical information is not recorded (like velocity, acceleration, etc.)\n",
    "# But we calculated these information for you\n",
    "\n",
    "first_frame = replay.get_frame(1)   # == replay.frame_info[0]\n",
    "print(\"frame_id:\", first_frame.frame_id)\n",
    "print(\"frame_time:\", first_frame.frame_time)\n",
    "print(\"transform:\", first_frame.transform)\n",
    "print(\"velocity:\", first_frame.velocity)\n",
    "print(\"acceleration:\", first_frame.acceleration)\n",
    "print(\"action:\", first_frame.action)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Actor id: 201\n",
      "Actor transform: Transform(location=Location(x=-1.9299199999999999, y=79.2626, z=-0.00502571), rotation=Rotation(pitch=0.0, yaw=0.0, roll=90.0221))\n",
      "Actor velocity: Vector3D(x=0, y=0, z=0)\n",
      "Actor acceleration: Vector3D(x=0, y=0, z=0)\n",
      "Actor action: Action(steering=0.0, throttle=0.0, brake=0.0, handbrake=False, gear=0, speed=None, type='vehicle')\n"
     ]
    }
   ],
   "source": [
    "# You can also get an actor-wise view instead\n",
    "# pass `use_carla_api=True` to get Carla instances\n",
    "\n",
    "actor_info = first_frame.get_info_by_id(201, use_carla_api=False)\n",
    "print(\"Actor id:\", actor_info.id)\n",
    "print(\"Actor transform:\", actor_info.transform)\n",
    "print(\"Actor velocity:\", actor_info.velocity)\n",
    "print(\"Actor acceleration:\", actor_info.acceleration)\n",
    "print(\"Actor action:\", actor_info.action)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Collision info"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# There is very little information about the collision info in the replay file\n",
    "# We can only know at which frame the collision happens, and the id of the actors\n",
    "# Only actor that attached with a collision sensor will record the collision information\n",
    "\n",
    "print(*replay.get_collision_frames()[:5], sep=\"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Trajectory"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We provide a function to return the trajectory of an actor\n",
    "# The trajectory is a list of `Transform`\n",
    "\n",
    "traj = replay.get_actor_trajectory(201)\n",
    "print(*traj[:5], sep=\"\\n\")\n",
    "\n",
    "# Note: \n",
    "# 1. The first frame's location may not be the same as the spawn point\n",
    "# 2. We removed duplicated transforms (same location and rotation), this may cause some problem"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "marllib",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
